﻿using Microsoft.Win32;
using PrinterMonitorSvc.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace PrinterMonitorSvc.Common
{
    /// <summary>
    /// WIndow帮助类(服务安装：System.Configuration.Install)
    /// </summary>
    public static class WinHelper
    {
        #region 修改计算机名称
        /// <summary>
        /// 修改计算机名称(ModifyComputerName(5, "新名称") != 0修改成功)
        /// </summary>
        /// <param name="type"></param>
        /// <param name="lpComputerName"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll", EntryPoint = "SetComputerNameEx")]
        public static extern int ModifyComputerName(int type, string lpComputerName);
        #endregion

        #region 指定类型的端口是否已经被使用了
        /// <summary>
        /// 指定类型的端口是否已经被使用了
        /// </summary>
        /// <param name="port">端口号</param>
        /// <param name="type">端口类型</param>
        /// <returns></returns>
        public static bool IsPortOccuped(int port, PortTypeEnum type)
        {
            bool flag = false;
            IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipendpoints = null;
            if (type == PortTypeEnum.TCP)
            {
                ipendpoints = properties.GetActiveTcpListeners();
            }
            else
            {
                ipendpoints = properties.GetActiveUdpListeners();
            }
            foreach (IPEndPoint ipendpoint in ipendpoints)
            {
                if (ipendpoint.Port == port)
                {
                    flag = true;
                    break;
                }
            }
            ipendpoints = null;
            properties = null;
            return flag;
        }
        #endregion

        #region 是否开机自启
        /// <summary>  
        /// 是否开机自启(注册表方式)
        /// </summary>  
        /// <param name="isAuto">true:开机启动,false:不开机自启</param> 
        /// <param name="executableName">可执行文件名称(写入启动项)</param>
        /// <param name="executablePath">可执行文件完整路径(如：Application.ExecutablePath,非自启时可不传)</param>
        /// <param name="registryKey">Windows 注册表中的项级节点(默认为：HKEY_LOCAL_MACHINE；只针对当前用户：Registry.CurrentUser)</param>
        public static void AutoStartByRegedit(bool isAuto, string executableName, string executablePath = null, RegistryKey registryKey = null)
        {
            if (string.IsNullOrEmpty(executableName))
            {
                throw new ArgumentException("The executableName cannot be empty");
            }
            if (isAuto && string.IsNullOrEmpty(executablePath))
            {
                throw new ArgumentException("The executablePath cannot be empty");
            }
            if (null == registryKey)
            {
                registryKey = Registry.LocalMachine;
            }
            RegistryKey rk = registryKey.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
            if (isAuto)
            {
                rk.SetValue(executableName, executablePath);
            }
            else
            {
                rk.DeleteValue(executableName, false);
            }
            rk.Close();
            registryKey.Close();
        }

        /// <summary>  
        /// 是否开机自启(文件方式)
        /// </summary>  
        /// <param name="isAuto">true:开机启动,false:不开机自启</param> 
        /// <param name="executableName">可执行文件名称(写入启动项)</param>
        /// <param name="executablePath">可执行文件完整路径(如：Application.ExecutablePath,非自启时可不传)</param>
        public static void AutoStartByFile(bool isAuto, string executableName, string executablePath = null)
        {
            if (string.IsNullOrEmpty(executableName))
            {
                throw new ArgumentException("The executableName cannot be empty");
            }
            if (isAuto && string.IsNullOrEmpty(executablePath))
            {
                throw new ArgumentException("The executablePath cannot be empty");
            }

            string startupPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonStartup);

            if (isAuto)
            {
                File.Copy(executablePath, startupPath + $"\\{executableName}.exe.lnk", true);
            }
            else
            {
                var file = startupPath + $"\\{executableName}.exe.lnk";
                if (File.Exists(file))
                {
                    File.Delete(file);
                }
            }
        }
        #endregion

        #region 重启计算机
        /// <summary>
        /// 重启计算机
        /// </summary>
        public static void Restart()
        {
            using (Process process = new Process())
            {
                process.StartInfo.FileName = "cmd.exe";//启动cmd命令
                process.StartInfo.UseShellExecute = false;//是否使用系统外壳程序启动进程
                process.StartInfo.RedirectStandardInput = true;//是否从流中读取
                process.StartInfo.RedirectStandardOutput = true;//是否写入流
                process.StartInfo.RedirectStandardError = true;//是否将错误信息写入流
                process.StartInfo.CreateNoWindow = true;//是否在新窗口中启动进程
                process.Start();//启动进程
                process.StandardInput.WriteLine("shutdown -r -t 0");//执行重启计算机命令
            }

        }
        #endregion

        #region 是否是管理员权限运行
        /// <summary>
        /// 是否是管理员权限运行
        /// </summary>
        /// <returns></returns>
        public static bool IsAdministrator()
        {
            WindowsIdentity identity = WindowsIdentity.GetCurrent();
            WindowsPrincipal principal = new WindowsPrincipal(identity);
            return principal.IsInRole(WindowsBuiltInRole.Administrator);
        }
        #endregion

        #region 获取计算机名
        /// <summary>
        /// 获取计算机名
        /// </summary>
        /// <returns></returns>
        public static string GetMachineName()
        {
            return Environment.MachineName;
        }
        #endregion

        #region WIN Service
        /// <summary>
        /// 获取服务安装路径
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <returns></returns>
        public static string GetWindowsServiceInstallPath(string serviceName)
        {
            string key = @"SYSTEM\CurrentControlSet\Services\" + serviceName;
            string path = Registry.LocalMachine.OpenSubKey(key).GetValue("ImagePath").ToString();
            //替换掉双引号   
            path = path.Replace("\"", string.Empty);

            FileInfo fi = new FileInfo(path);
            return fi.Directory.ToString();
        }

        /// <summary>
        /// 新增服务配置
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="name">属性名称</param>
        /// <param name="value">属性值</param>
        public static void AddWindowsServiceConfig(string serviceName, string name, object value)
        {
            string key = @"SYSTEM\CurrentControlSet\Services\" + serviceName;
            Registry.LocalMachine.CreateSubKey(key).SetValue(name, value, RegistryValueKind.String);
        }

        /// <summary>
        /// 获取服务配置
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="name">属性名称</param>
        public static object GetWindowsServiceConfig(string serviceName, string name)
        {
            string key = @"SYSTEM\CurrentControlSet\Services\" + serviceName;
            return Registry.LocalMachine.OpenSubKey(key).GetValue(name);
        }

        /// <summary>
        /// 判断服务是否存在
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <returns></returns>
        public static bool IsServiceExisted(string serviceName)
        {
            ServiceController[] services = ServiceController.GetServices();
            foreach (ServiceController sc in services)
            {
                if (sc.ServiceName.ToLower() == serviceName.ToLower())
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 安装服务
        /// </summary>
        /// <param name="serviceFilePath">服务路径</param>
        public static void InstallService(string serviceFilePath)
        {
            using (AssemblyInstaller installer = new AssemblyInstaller())
            {
                installer.UseNewContext = true;
                installer.Path = serviceFilePath;
                IDictionary savedState = new Dictionary<object, object>();
                installer.Install(savedState);
                installer.Commit(savedState);
            }
        }

        /// <summary>
        /// 卸载服务
        /// </summary>
        /// <param name="serviceFilePath">服务路径</param>
        public static void UninstallService(string serviceFilePath)
        {
            using (AssemblyInstaller installer = new AssemblyInstaller())
            {
                installer.UseNewContext = true;
                installer.Path = serviceFilePath;
                installer.Uninstall(null);
            }
        }
        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        public static void ServiceStart(string serviceName)
        {
            using (ServiceController control = new ServiceController(serviceName))
            {
                if (control.Status == ServiceControllerStatus.Stopped)
                {
                    control.Start();
                }
            }
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        public static void ServiceStop(string serviceName)
        {
            using (ServiceController control = new ServiceController(serviceName))
            {
                if (control.Status == ServiceControllerStatus.Running)
                {
                    control.Stop();
                }
            }
        }

        /// <summary>
        /// 是否允许服务与桌面交互（必须为LocalSystem账户）
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="isEnable">是否启用</param>
        public static void DesktopInteract(string serviceName, bool isEnable)
        {
            ManagementObject myService = new ManagementObject(string.Format("Win32_Service.Name='{0}'", serviceName));
            ManagementBaseObject changeMethod = myService.GetMethodParameters("Change");
            changeMethod["DesktopInteract"] = isEnable;
            myService.InvokeMethod("Change", changeMethod, null);
        }
        #endregion

        #region 加入AD域
        /// <summary>
        /// 加入AD域
        /// </summary>
        /// <param name="domainName">需要加入的域名</param>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <returns>返回错误信息</returns>
        public static string JoinDomain(string domainName, string username, string password)
        {
            string err = string.Empty;
            // Invoke WMI to join the domain
            using (ManagementObject wmiObject = new ManagementObject(new ManagementPath("Win32_ComputerSystem.Name='" + Environment.MachineName + "'")))
            {
                try
                {
                    // Obtain in-parameters for the method
                    ManagementBaseObject inParams = wmiObject.GetMethodParameters("JoinDomainOrWorkgroup");
                    inParams["Name"] = domainName;
                    inParams["Password"] = username;
                    inParams["UserName"] = password;
                    inParams["AccountOU"] = null;
                    inParams["FJoinOptions"] = 3;
                    // Execute the method and obtain the return values.
                    ManagementBaseObject outParams = wmiObject.InvokeMethod("JoinDomainOrWorkgroup", inParams, null);

                    switch (outParams["ReturnValue"].ToString())
                    {
                        case "5":
                            err = "Access is denied";
                            break;
                        case "87":
                            err = "The parameter is incorrect";
                            break;
                        case "110":
                            err = "The system cannot open the specified object";
                            break;
                        case "1323":
                            err = "Unable to update the password";
                            break;
                        case "1326":
                            err = "Logon failure: unknown username or bad password";
                            break;
                        case "1355":
                            err = "The specified domain either does not exist or could not be contacted";
                            break;
                        case "2224":
                            err = "The account already exists";
                            break;
                        case "2691":
                            err = "The machine is already joined to the domain";
                            break;
                        case "2692":
                            err = "The machine is not currently joined to a domain";
                            break;
                    }
                }
                catch (ManagementException e)
                {
                    err = e.Message;
                }
                return err;
            }
        }
        #endregion

        /// <summary>    
        /// 确认电脑上是否安装有某个程序  
        /// </summary>    
        /// <param name="softWareName">程序安装后的名称</param>  
        /// <returns>true: 有安裝, false:沒有安裝</returns>    
        public static bool CheckSoftWareInstallState(List<string> list)
        {
            Microsoft.Win32.RegistryKey uninstallNode =
                Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths",
                Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree,
                System.Security.AccessControl.RegistryRights.ReadKey);
            foreach (string subKeyName in uninstallNode.GetSubKeyNames())
            {
                Microsoft.Win32.RegistryKey subKey = uninstallNode.OpenSubKey(subKeyName);
                object displayName = subKey.GetValue("Path");
                if (displayName != null)
                {
                    if (list.Any(s => displayName.ToString().Contains(s)))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>    
        /// 确认电脑上是否安装有某个程序,没有返回空，否则返回执行程序的完整地址
        /// </summary>    
        /// <param name="dirName">程序安装后的目录名称</param>
        /// <param name="exeName">执行程序的名称</param>
        /// <returns></returns>
        public static string GetSoftWareInstallPos(string dirName, string exeName)
        {
            Microsoft.Win32.RegistryKey uninstallNode =
                Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths",
                Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree,
                System.Security.AccessControl.RegistryRights.ReadKey);
            foreach (string subKeyName in uninstallNode.GetSubKeyNames())
            {
                Microsoft.Win32.RegistryKey subKey = uninstallNode.OpenSubKey(subKeyName);
                object displayName = subKey.GetValue("Path");
                if (displayName != null)
                {
                    if (displayName.ToString().Contains(dirName))
                    {
                        var exePath = displayName + exeName;
                        return File.Exists(exePath) ? exePath : null;
                    }
                }
            }
            return null;
        }
    }
}
